import { AstTreeUtils } from "arkanalyzer";
import { ts, NodePredicate } from "qvog-dsl";

import { CallExpression, native, HomeCheckHint } from 'qvog-dsl';

const SEVERITY = 2;
const DOC_PATH = '';
const DESCRIPTION = 'When the third parameter KeyGenerator of ForEach uses the default key generation rule (index + \'__\' + JSON.stringify(item)), inserting a new array item triggers component recreation for all subsequent items, leading to poor performance with large datasets or complex components due to lack of component reuse.';

const FREQUENCYFUNCS = ['onTouch', 'onItemDragMove', 'onDragMove', 'onMouse', 'onVisibleAreaChange', 'onAreaChange', 'onScroll', 'onActionUpdate'];

export default native<HomeCheckHint>()()
    .match(CallExpression)
    .when((node: ts.CallExpression): boolean => {
        let callExpression = node;
        if (ts.isCallExpression(callExpression)) {
            let sig = callExpression.expression;
            if (sig.kind === ts.SyntaxKind.PropertyAccessExpression) {
                let propertyAcc = sig as ts.PropertyAccessExpression;
                if (FREQUENCYFUNCS.includes(propertyAcc.name.escapedText.toString())) {
                    let args = callExpression.arguments;
                    return parseArgs(args);
                }
            }
        }
        return false;
    })
    .report({
        severity: SEVERITY,
        description: DESCRIPTION,
        docPath: DOC_PATH,
    });

function parseArgs(args: ts.NodeArray<ts.Expression>): boolean {
    for (const arg of args) {
        if (arg.kind !== 218) { continue };
        const arrowFunction = arg as ts.ArrowFunction;

        if (arrowFunction.body.kind !== 241) { continue };
        const block = arrowFunction.body as ts.Block;

        if (parseStmts(block.statements)) {
            return true;
        }
    }

    return false;
}

function parseStmts(stmts: ts.NodeArray<ts.Statement>): boolean {
    for (const stmt of stmts) {
        if (stmt.kind !== 244) { continue };
        const exprStmt = stmt as ts.ExpressionStatement;

        if (exprStmt.expression.kind !== 212) { continue };
        const callExpr = exprStmt.expression as ts.CallExpression;

        if (parseCallExpr(callExpr)) {
            return true;
        }
    }

    return false;
}

function parseCallExpr(callExpr: ts.CallExpression): boolean {
    let sig = callExpr.expression;
    if (sig.kind === ts.SyntaxKind.PropertyAccessExpression) {
        let propertyAcc = sig as ts.PropertyAccessExpression;
        let expr = propertyAcc.expression;
        if (expr.kind === 79) {
            let iden = expr as ts.Identifier;
            if (iden.escapedText === 'console') {
                return true;
            }
        }
    }
    return false;
}

